/**
 * Class: EventFile
 *
 * Purpose: 
 *
 * Created: Feb 6, 2010 @ 10:01:24 PM
 * @author Ken Scott
 */
package org.openfantasia.util.listener;

import org.openfantasia.util.TextUtils;

import java.io.*;
import java.util.Iterator;
import java.util.List;

public class EventFile {

	private File file;

	private PrintWriter writer;

	private LineNumberReader reader;


	public EventFile() {
	}


	public EventFile(File file) {
		this.file = file;
	}


	public File getFile() {
		return file;
	}


	public void setFile(File file) {
		this.file = file;
	}


	public void beginPlayback() throws IOException {
		reader = new LineNumberReader(new FileReader(file));
	}


	public void beginRecording() throws IOException {
		writer = new PrintWriter(new FileWriter(file));
	}


	public void close() throws IOException {
		if (reader != null) {
			reader.close();
			reader = null;
		}
		if (writer != null) {
			writer.close();
			writer = null;
		}
	}


	public void addEvent(Event event) {
		StringBuilder sb = new StringBuilder();

		sb.append(event.getClass().getName()).append("\t");
		sb.append(Double.toString(event.getTime())).append("\t");
		sb.append(event.getChannel()).append("\t");

		if (event instanceof BooleanScalar) {
			boolean value = ((BooleanScalar) event).getValue();
			sb.append(Boolean.toString(value)).append("\t");
		}
		if (event instanceof IntegerScalar) {
			int value = ((IntegerScalar) event).getValue();
			sb.append(Integer.toString(value)).append("\t");
		}
		else if (event instanceof FloatScalar) {
			float value = ((FloatScalar) event).getValue();
			sb.append(Float.toString(value)).append("\t");
		}
		else if (event instanceof FloatArray) {
			float[] value = ((FloatArray) event).getValue();
			sb.append(Integer.toString(value.length)).append("\t");
			for (float val : value) {
				sb.append(Float.toString(val)).append("\t");
			}
		}
		else if (event instanceof FloatGrid) {
			float[][] value = ((FloatGrid) event).getValue();
			sb.append(Integer.toString(value.length)).append("\t");
			sb.append(Integer.toString(value[0].length)).append("\t");
			for (float[] v1 : value) {
				for (float v : v1) {
					sb.append(Float.toString(v)).append("\t");
				}
			}
		}
		else if (event instanceof FloatMatrix) {
			float[][][] value = ((FloatMatrix) event).getValue();
			sb.append(Integer.toString(value.length)).append("\t");
			sb.append(Integer.toString(value[0].length)).append("\t");
			sb.append(Integer.toString(value[0][0].length)).append("\t");
			for (float[][] v0 : value) {
				for (float[] v1 : v0) {
					for (float v : v1) {
						sb.append(Float.toString(v)).append("\t");
					}
				}
			}
		}
		else if (event instanceof DoubleScalar) {
			double value = ((DoubleScalar) event).getValue();
			sb.append(Double.toString(value)).append("\t");
		}
		else if (event instanceof DoubleArray) {
			double[] value = ((DoubleArray) event).getValue();
			sb.append(Integer.toString(value.length)).append("\t");
			for (double val : value) {
				sb.append(Double.toString(val)).append("\t");
			}
		}
		else if (event instanceof DoubleGrid) {
			double[][] value = ((DoubleGrid) event).getValue();
			sb.append(Integer.toString(value.length)).append("\t");
			sb.append(Integer.toString(value[0].length)).append("\t");
			for (double[] v1 : value) {
				for (double v : v1) {
					sb.append(Double.toString(v)).append("\t");
				}
			}
		}
		else if (event instanceof DoubleMatrix) {
			double[][][] value = ((DoubleMatrix) event).getValue();
			sb.append(Integer.toString(value.length)).append("\t");
			sb.append(Integer.toString(value[0].length)).append("\t");
			sb.append(Integer.toString(value[0][0].length)).append("\t");
			for (double[][] v0 : value) {
				for (double[] v1 : v0) {
					for (double v : v1) {
						sb.append(Double.toString(v)).append("\t");
					}
				}
			}
		}

		writer.println(sb.toString());
	}


	public Event nextEvent() throws IOException {
		Event result = null;

		String s = reader.readLine();
		if(s != null) {
			List<String> tokens = TextUtils.tokenize(s, "\t", false);
			Iterator<String> tIter = tokens.iterator();
			String sClass = tIter.next();
			String sTime = tIter.next();
			String sChannel = tIter.next();
			try {
				result = (Event) Class.forName(sClass).newInstance();
			}
			catch (Exception e) {
				throw new RuntimeException("Error while instantiating " + sClass, e);
			}

			result.setTime(Double.parseDouble(sTime));
			result.setChannel(sChannel);

			if (result instanceof BooleanScalar) {
				((BooleanScalar) result).setValue(Boolean.parseBoolean(tIter.next()));
			}
			else if (result instanceof IntegerScalar) {
				((IntegerScalar) result).setValue(Integer.parseInt(tIter.next()));
			}
			else if (result instanceof FloatScalar) {
				((FloatScalar) result).setValue(Float.parseFloat(tIter.next()));
			}
			else if (result instanceof FloatArray) {
				int len = Integer.parseInt(tIter.next());
				float[] val = new float[len];
				for (int i = 0; i < len; i++) {
					val[i] = Float.parseFloat(tIter.next());
				}
				((FloatArray) result).setValue(val);
			}
			else if (result instanceof FloatGrid) {
				int len0 = Integer.parseInt(tIter.next());
				int len1 = Integer.parseInt(tIter.next());
				float[][] val = new float[len0][len1];
				for (int i = 0; i < len0; i++) {
					for (int j = 0; j < len1; j++) {
						val[i][j] = Float.parseFloat(tIter.next());
					}
				}
				((FloatGrid) result).setValue(val);
			}
			else if (result instanceof FloatMatrix) {
				int len0 = Integer.parseInt(tIter.next());
				int len1 = Integer.parseInt(tIter.next());
				int len2 = Integer.parseInt(tIter.next());
				float[][][] val = new float[len0][len1][len2];
				for (int i = 0; i < len0; i++) {
					for (int j = 0; j < len1; j++) {
						for (int k = 0; k < len2; k++) {
							val[i][j][k] = Float.parseFloat(tIter.next());
						}
					}
				}
				((FloatMatrix) result).setValue(val);
			}
			else if (result instanceof DoubleScalar) {
				((DoubleScalar) result).setValue(Double.parseDouble(tIter.next()));
			}
			else if (result instanceof DoubleArray) {
				int len = Integer.parseInt(tIter.next());
				double[] val = new double[len];
				for (int i = 0; i < len; i++) {
					val[i] = Double.parseDouble(tIter.next());
				}
				((DoubleArray) result).setValue(val);
			}
			else if (result instanceof DoubleGrid) {
				int len0 = Integer.parseInt(tIter.next());
				int len1 = Integer.parseInt(tIter.next());
				double[][] val = new double[len0][len1];
				for (int i = 0; i < len0; i++) {
					for (int j = 0; j < len1; j++) {
						val[i][j] = Double.parseDouble(tIter.next());
					}
				}
				((DoubleGrid) result).setValue(val);
			}
			else if (result instanceof DoubleMatrix) {
				int len0 = Integer.parseInt(tIter.next());
				int len1 = Integer.parseInt(tIter.next());
				int len2 = Integer.parseInt(tIter.next());
				double[][][] val = new double[len0][len1][len2];
				for (int i = 0; i < len0; i++) {
					for (int j = 0; j < len1; j++) {
						for (int k = 0; k < len2; k++) {
							val[i][j][k] = Double.parseDouble(tIter.next());
						}
					}
				}
				((DoubleMatrix) result).setValue(val);
			}
		}

		return result;
	}
}
